﻿// Copyright (C) 2012 Jeff Tanner <jeff00seattle@gmail.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

using System;
using System.IO;
using System.Diagnostics;
using System.Configuration;
using System.Configuration.Install;
using System.ComponentModel;
using System.Threading;
using System.Collections.Generic;
using System.Web;

using WindowsAzure_REST;

namespace WindowsAzure_FileBackup_Common
{
    partial class Common
    {
        public static StorageEndpoint   WindowsAzureStorageBlobContainerEndpoint { get; set; }
        public static bool              WindowsAzureStorageBlobContainerDelete { get; set; }
        public static int               WindowsAzureStorageBlobContainerDeleteSleep { get; set; }

        /// <summary>
        /// Create blob container
        /// </summary>
        public void BlobContainerCreate()
        {
            try
            {
                EventLogEntryType type =
                  (Common.BlobREST.CreateContainer(Common.WindowsAzureStorageBlobContainerName)) ? EventLogEntryType.Information : EventLogEntryType.Error;

                this.EventLog.WriteEntry(
                        String.Format(
                            "Blob Container Create: {0}",
                            Common.WindowsAzureStorageBlobContainerName
                            ),
                        type
                        );
            }
            catch (Exception ex)
            {
                this.EventLog.WriteEntry(
                    String.Format("Blob Container Create: Exception: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
        }

        /// <summary>
        /// Create blob for file
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="blobPath">The Blob path.</param>
        public void BlobCreate(string rootDirectory, string filePath, string blobPath)
        {
            this.EventLog.WriteEntry(
                    String.Format(
                        "Blob Create: {0} | {1} ",
                        filePath,
                        blobPath
                        )
                );

            FileStream fs = null;
            try
            {
                bool response = false;
                string blobPathEncoded = Uri.EscapeUriString(blobPath);

                SortedList<string, string> fileMetadata = new SortedList<string, string>();
                Common.SetupMetadata(rootDirectory, filePath, fileMetadata);

                EnumFileSystemType fileSystemType = this.getFileSystemType(filePath);
                if (EnumFileSystemType.File == fileSystemType)
                {
                    fs = File.OpenRead(filePath);
                    FileInfo fi = new FileInfo(filePath);

                    byte[] binary = this.readFileFully(fs, (int)fi.Length);
                    Common.BlobREST.PutBlob(Common.WindowsAzureStorageBlobContainerName, blobPathEncoded, binary.ToString());

                    if (null != fs)
                    {
                        fs.Close();
                        fs = null;
                    }
                }
                else if (EnumFileSystemType.Directory == fileSystemType)
                {
                    response = Common.PutBlobFolder(blobPath);
                }
                else
                {
                    string errorMsg =
                        String.Format(
                            "Blob Create: Unknown File Type for creating this Blob: {0}",
                            blobPath
                            );

                    this.EventLog.WriteEntry(
                        errorMsg,
                        EventLogEntryType.Error
                        );

                    throw new ApplicationException(errorMsg);
                }

                // Provided file metadata to blob
                response = Common.BlobREST.SetBlobMetadata(Common.WindowsAzureStorageBlobContainerName, blobPath, fileMetadata);

                EventLogEntryType type =
                  (response) ? EventLogEntryType.Information : EventLogEntryType.Error;

                this.EventLog.WriteEntry(
                        String.Format(
                            "Blob Create: {0}",
                            Common.WindowsAzureStorageBlobContainerName
                            ),
                        type
                        );

            }
            catch (ApplicationException)
            {
                throw;
            }
            catch (Exception ex)
            {
                this.EventLog.WriteEntry(
                    String.Format("Blob Create: Exception: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
            finally
            {
                if (null != fs)
                {
                    fs.Close();
                }
            }
        }

        /// <summary>
        /// Delete blob
        /// </summary>
        /// <param name="blobPath">The Blob path.</param>
        public void BlobDelete(string filePath, string blobPath)
        {
            this.EventLog.WriteEntry(
                    String.Format(
                        "Blob Delete: {0} | {1} ",
                        filePath,
                        blobPath
                        )
                );

            try
            {
                EnumFileSystemType fileType = this.getFileSystemType(filePath);
                if (EnumFileSystemType.File == fileType)
                {
                }
                else if (EnumFileSystemType.Directory == fileType)
                {
                    blobPath = Common.BlobFolderName(blobPath);
                }
                else
                {
                    string errorMsg =
                        String.Format(
                            "Blob Delete: Unknown File Type for deleting this Blob: {0}",
                            blobPath
                            );

                    this.EventLog.WriteEntry(
                        errorMsg,
                        EventLogEntryType.Error
                        );

                    throw new ApplicationException(errorMsg);
                }

                EventLogEntryType type =
                  (Common.BlobREST.DeleteBlob(Common.WindowsAzureStorageBlobContainerName, blobPath)) ? EventLogEntryType.Information : EventLogEntryType.Error;

                this.EventLog.WriteEntry(
                        String.Format(
                            "Blob Delete: {0}",
                            blobPath
                            ),
                        type
                        );
            }
            catch (ApplicationException)
            {
                throw;
            }
            catch (Exception ex)
            {
                this.EventLog.WriteEntry(
                    String.Format("Blob Delete: Exception: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
        }

        /// <summary>
        /// BLOBs the change.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="blobPath">The Blob path.</param>
        private void blobChange(
            string filePath,
            string blobPath
        )
        {
            this.EventLog.WriteEntry(
                    String.Format(
                        "Blob Change: {0} | {1} ",
                        filePath,
                        blobPath
                        )
                );
        }

        /// <summary>
        /// BLOBs the rename.
        /// </summary>
        /// <param name="filePathOld">The file path old.</param>
        /// <param name="blobPathOld">The Blob path old.</param>
        /// <param name="filePath">The file path.</param>
        /// <param name="blobPath">The Blob path.</param>
        public void BlobRename(
            string filePathOld,
            string blobPathOld,
            string filePath,
            string blobPath
        )
        {
            this.EventLog.WriteEntry(
                    String.Format(
                        "Blob Rename: {0} {1} | {2} {3}",
                        filePathOld,
                        blobPathOld,
                        filePath,
                        blobPath
                        )
                );

            try
            {
                string blobName = blobPathOld;
                string blobBody = Common.BlobREST.GetBlob(Common.WindowsAzureStorageBlobContainerName, blobName);
                if (!String.IsNullOrEmpty(blobBody))
                {
                    Common.BlobREST.DeleteBlob(Common.WindowsAzureStorageBlobContainerName, blobName);
                }
                else
                {
                    blobName = Common.BlobFolderName(blobPathOld);
                    blobBody = Common.BlobREST.GetBlob(Common.WindowsAzureStorageBlobContainerName, blobName);
                    if (!String.IsNullOrEmpty(blobBody))
                    {
                        Common.BlobREST.DeleteBlob(Common.WindowsAzureStorageBlobContainerName, blobName);
                    }
                }

                DirectoryInfo rootInfo = new DirectoryInfo(Common.WindowsAzureFileBackupRootDir.Replace(@"\", @"\\"));
                string rootPath = rootInfo.FullName;

                this.BlobCreate(rootPath, filePath, blobPath);
            }
            catch (Exception ex)
            {
                this.EventLog.WriteEntry(
                    String.Format("Blob Rename: Exception: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Retrieves all blobs in backup container. </summary>
        ////////////////////////////////////////////////////////////////////////////////////////////////////

        public List<string> RetrieveContainerBlobs()
        {
            return Common.BlobREST.ListBlobs(Common.WindowsAzureStorageBlobContainerName);
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Deletes all blobs in backup container. </summary>
        ////////////////////////////////////////////////////////////////////////////////////////////////////

        public static void DeleteContainerBlobs()
        {
            List<string> blobNames = Common.BlobREST.ListBlobs(Common.WindowsAzureStorageBlobContainerName);

            foreach (string blobName in blobNames)
            {
                Common.BlobREST.DeleteBlob(Common.WindowsAzureStorageBlobContainerName, blobName);
            }
        }

        /// <summary>
        /// Puts pseudo folder within a blob container.
        /// </summary>
        /// <param name="this.Name">Name of a blob.</param>
        /// <param name="blobContents">The Blob contents.</param>
        /// <returns></returns>
        public static bool PutBlobFolder(string blobPath)
        {
            return Common.BlobREST.PutBlob(Common.WindowsAzureStorageBlobContainerName, Common.BlobFolderName(blobPath), String.Empty);
        }

        /// <summary>
        /// BLOBs the name of the folder.
        /// </summary>
        /// <param name="blobPath">The Blob path.</param>
        /// <returns></returns>
        public static string BlobFolderName(string blobPath)
        {
            char[] charTrim = { '\\', '/' };
            string trimmed = blobPath.TrimEnd(charTrim);
            return String.Format("{0}/$$$.$$$", trimmed);
        }
    }
}
